package org.jumbo.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Calendar;
import java.util.Date;

import com.coremedia.iso.IsoFile;
import com.drew.imaging.ImageMetadataReader;
import com.drew.metadata.Metadata;
import com.drew.metadata.exif.ExifSubIFDDirectory;

public class OrganizerWorker extends Thread {
  private String srcBaseDir;
  private String dstBaseDir;
  private boolean addDayDir;
  // This variable is to determine whether it's Image|Video/YYYY/MM/DD or YYYY/MM/DD/Image|Video
  // May need to come up with something better.
  private boolean typeFirst;
  private File[] srcFiles;
  private int startIndex;
  private int endIndex;
  public void setSrcBaseDir(String srcBaseDir) {
    this.srcBaseDir = srcBaseDir;
  }
  public String getSrcBaseDir() {
    return srcBaseDir;
  }
  public String getDstBaseDir() {
    return dstBaseDir;
  }
  public void setDstBaseDir(String dstBaseDir) {
    this.dstBaseDir = dstBaseDir;
  }
  public boolean isAddDayDir() {
    return addDayDir;
  }
  public void setAddDayDir(boolean addDayDir) {
    this.addDayDir = addDayDir;
  }
  public boolean isTypeFirst() {
    return typeFirst;
  }
  public void setTypeFirst(boolean typeFirst) {
    this.typeFirst = typeFirst;
  }
  public void setSrcFiles(File[] srcFiles) {
    this.srcFiles = srcFiles;
  }
  public File[] getSrcFiles() {
    return srcFiles;
  }
  public void setStart(int start) {
    this.startIndex = start;
  }
  public int getStart() {
    return startIndex;
  }
  public void setEnd(int end) {
    this.endIndex = end;
  }
  public int getEnd() {
    return endIndex;
  }
  public void run() {
    System.out.println("Thread started: " + this.getId());
    organizeMediaFile();
  }
  public OrganizerWorker(String srcBaseDir, String dstBaseDir, boolean addDayDir,
      boolean typeFirst, File[] srcFiles, int startI, int endI) {
    setSrcBaseDir(srcBaseDir);
    setDstBaseDir(dstBaseDir);
    setAddDayDir(addDayDir);
    setTypeFirst(typeFirst);
    setSrcFiles(srcFiles);
    setStart(startI);
    setEnd(endI);
  }
  public void organizeMediaFile() {
    //File[] srcFiles = getSourceFiles();
    
    for (int i = getStart(); i < getEnd(); i++) {
      if (srcFiles[i].isFile()) {
        String fileName = srcFiles[i].getName();
        long fileSize = srcFiles[i].length();
        String srcFilePath = getSrcBaseDir() + File.separator + fileName;
        if (fileName.toLowerCase().endsWith(".jpg") ||
            fileName.toLowerCase().endsWith(".png") ||
            fileName.toLowerCase().endsWith(".gif") ||
            fileName.toLowerCase().endsWith(".tiff")) {
          copyImageFile(fileName, fileSize, srcFilePath);
        } else if (fileName.toLowerCase().endsWith(".mp4") ||
            fileName.toLowerCase().endsWith(".3gp")) {
          copyVideoFile(fileName, fileSize, srcFilePath);
        } else {
          System.out.println("file type not supported, skip processing: " + fileName);
        }
      }
    }
  }
  private void copyVideoFile(String fileName, long fileSize, String srcFilePath) {
    //System.out.println("video file " + fileName);
    try {
      FileChannel fc = new FileInputStream(srcFilePath).getChannel();
      try {
        IsoFile isoFile = new IsoFile(fc);
        Date date = null;
        if (isoFile != null) {
          date = isoFile.getMovieBox().getMovieHeaderBox().getCreationTime();
        }
        createDirAndCopy(fileName, srcFilePath, date, "Videos", fileSize);
        isoFile.close();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      try {
        fc.close();
      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    } catch (FileNotFoundException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
  private void copyImageFile(String fileName, long fileSize, String srcFilePath) {
    //System.out.println("image file " + fileName);
    
    File imageFile = new File(srcFilePath);
    try {
      Metadata imageMetadata = ImageMetadataReader.readMetadata(imageFile);
      ExifSubIFDDirectory directory = imageMetadata.getDirectory(ExifSubIFDDirectory.class);
      Date date = null;
      if (directory != null) {
        date = directory.getDate(ExifSubIFDDirectory.TAG_DATETIME_ORIGINAL);
      }
      createDirAndCopy(fileName, srcFilePath, date, "Images", fileSize);
      
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  private String appendFileSeparator(String baseDir) {
    return baseDir + File.separator;
  }
  private void createDirAndCopy(String fileName,
      String srcFilePath, Date date, String fileType, long fileSize) throws IOException {
    String destDirPath;
    StringBuilder dstPathBuilder = new StringBuilder(appendFileSeparator(getDstBaseDir()));
    
    if (date != null) {
      Calendar calendar = Calendar.getInstance();
      calendar.setTime(date);
      StringBuilder datePathBuilder = new StringBuilder(
          appendFileSeparator(Integer.toString(calendar.get(Calendar.YEAR))));
      datePathBuilder.append(
          appendFileSeparator(Integer.toString(calendar.get(Calendar.MONTH) + 1)));
      if (isAddDayDir()) {
        datePathBuilder.append(appendFileSeparator(
            Integer.toString(calendar.get(Calendar.DAY_OF_MONTH))));
      }
      if (isTypeFirst()) {
        dstPathBuilder.append(appendFileSeparator(fileType)).append(datePathBuilder.toString());
      } else {
        dstPathBuilder.append(datePathBuilder.toString()).append(appendFileSeparator(fileType));
      }
      destDirPath = dstPathBuilder.toString();
    } else {
      if (isTypeFirst()) {
        dstPathBuilder.append(
            appendFileSeparator(fileType)).append(appendFileSeparator("no_date"));
      } else {
        dstPathBuilder.append(
            appendFileSeparator("no_date")).append(appendFileSeparator(fileType));
      }
      destDirPath = dstPathBuilder.toString();
    }
    File destDir = new File(destDirPath);
    if (!destDir.exists()) {
      if (!destDir.mkdirs()) {
        throw new IOException();
      }
    }
    String destPath = destDirPath + fileName;
    File destFile = new File(destPath);
    if (destFile.exists()) {
      // This dedup algorithm is very naive, need some more investigation on how do we
      // justify if the files are the same.
      System.out.println("File already exists, we need to check if they are the same.");
      if (fileSize != destFile.length()) {
        System.out.println("File sizes are different, add a sufix");
        destPath = destPath + "_1";
      } else {
        System.out.println("Files are the same, do nothing.");
      }
    }
    Files.copy(Paths.get(srcFilePath), Paths.get(destPath), StandardCopyOption.COPY_ATTRIBUTES);
  }
}
